package com.luo.ams.filter;

import com.alibaba.fastjson.JSON;
import com.luo.ams.security.AdminLoginPrincipal;
import com.luo.common.restful.JsonResult;
import com.luo.common.restful.ResponseCode;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
public class SSOFilter extends OncePerRequestFilter {
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${jwt.secretKey}")
    private String secretKey;
    @Value("${jwt.logoutKey}")
    private String logoutKey;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token = httpServletRequest.getHeader("Authorization");
        if (StringUtils.isBlank(token) || !token.startsWith(tokenHead)) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

        String authToken = token.substring(tokenHead.length());
        if (StringUtils.isBlank(authToken)) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

        Boolean member = stringRedisTemplate.boundSetOps(logoutKey).isMember(authToken);
        if (member){
            log.debug("已退出登录");
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

        Claims claims = null;
        try {
            claims = (Claims) Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken).getBody();
        } catch (ExpiredJwtException e) {
            JsonResult jsonResult = JsonResult.fail(ResponseCode.ERR_JWT_PARSE, "用户信息过期");
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println(jsonString);
            writer.flush();
            writer.close();
            return;
        } catch (MalformedJwtException e) {
            JsonResult jsonResult = JsonResult.fail(ResponseCode.ERR_JWT_PARSE, "解析失败");
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println(jsonString);
            writer.flush();
            writer.close();
            return;
        } catch (SignatureException e) {
            JsonResult jsonResult = JsonResult.fail(ResponseCode.ERR_JWT_PARSE, "解析失败");
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println(jsonString);
            writer.flush();
            writer.close();
            return;
        } catch (Throwable e) {
            JsonResult jsonResult = JsonResult.fail(ResponseCode.ERR_JWT_PARSE, "解析失败");
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println(jsonString);
            writer.flush();
            writer.close();
            return;
        }
        Long id = claims.get("id", Long.class);
        String username = claims.get("username", String.class);
        String authoritiesJson = claims.get("authorities", String.class);

        AdminLoginPrincipal principal = new AdminLoginPrincipal();
        principal.setId(id);
        principal.setUsername(username);

        List<SimpleGrantedAuthority> authorities = JSON.parseArray(
                authoritiesJson,SimpleGrantedAuthority.class
        );

        Authentication authentication = new UsernamePasswordAuthenticationToken(
                principal,null,authorities
        );
        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authentication);

        log.debug("放入上下文");
        filterChain.doFilter(httpServletRequest,httpServletResponse);

    }
}
